package com.transaction.manage.service;

import com.transaction.common.base.ResultVo;
import com.transaction.common.util.ConstUtil;
import com.transaction.common.util.DateUtil;
import com.transaction.common.util.JsonUtil;
import com.transaction.manage.localMapper.*;
import com.transaction.manage.model.dto.*;
import com.transaction.manage.model.vo.HandleVo;
import com.transaction.manage.model.vo.MarketVo;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BusinessHandleService {

    private static Logger LOGGER = LoggerFactory.getLogger(BusinessHandleService.class);

    @Autowired
    private FlowLogMapper flowLogMapper;

    @Autowired
    private FlowInfoMapper flowInfoMapper;

    @Autowired
    private LogDetailMapper logDetailMapper;

    @Autowired
    private AccountApplyMapper accountApplyMapper;

    @Autowired
    private ElContract43Mapper elContract43Mapper;

    @Autowired
    private TransApplyMapper transApplyMapper;

    @Autowired
    private NonResidentApplyMapper nonResidentApplyMapper;

    @Autowired
    private MarketMapper marketMapper;

    @Autowired
    private AccountStatusMapper accountStatusMapper;

    @Autowired
    private FundInfoMapper fundInfoMapper;

    @Autowired
    private FundYieldMapper fundYieldMapper;

    @Autowired
    private TransContractMapper transContractMapper;

    @Autowired
    private FundRelationMapper fundRelationMapper;

    @Autowired
    private SequenceMapper sequenceMapper;

    @Autowired
    private TaService taService;

    @Autowired
    private ElContract44Mapper elContract44Mapper;

    @Autowired
    private NonResidentCfmMapper nonResidentCfmMapper;

    @Autowired
    private AccountCfmMapper accountCfmMapper;

    @Autowired
    private TransCfmMapper transCfmMapper;


    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<FlowLog> selectDayEndHandleList(FlowLog flowLog) {
        return flowLogMapper.selectDayEndHandleList(flowLog);
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<FlowInfo> selectFlowStepCodeNameByFlowCode(String flowCode) {
        return flowInfoMapper.selectFlowStepCodeNameByFlowCode(flowCode);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insertFlowLog(String logCode, String channelCode, String handleDate, FlowInfo flowInfo) {
        LOGGER.info("开始插入流程处理日志表,渠道:{},处理日期:{},日志Code:{}", channelCode, handleDate, logCode);
        flowLogMapper.insertFlowLog(logCode, channelCode, handleDate, flowInfo);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateFlowLog(String logCode, HandleVo handleVo) {
        LOGGER.info("开始更新流程处理日志表,日志Code:{},处理结果为:{}", logCode, handleVo);
        flowLogMapper.updateFlowLog(logCode, handleVo);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Async
    public void asyncInsertLogDetail(String logCode, String errorMsg) {
        LogDetail logDetail = new LogDetail(logCode, errorMsg);
        LOGGER.info("插入日志详情表,日志Code:{},详细信息为:{}", logCode, errorMsg);
        logDetailMapper.insert(logDetail);
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public LogDetail selectLogDetailByLogCode(String logCode) {
        LogDetail logDetail = new LogDetail(logCode);
        LogDetail detail = logDetailMapper.selectOne(logDetail);
        return detail;
    }

    //查询处理步骤,循环处理
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public List<FlowInfo> selectFlowInfoList(String flowCode, Integer stepCode) {
        List<FlowInfo> flowInfoList = flowInfoMapper.selectFlowInfoList(new FlowInfo(flowCode, stepCode));
        return flowInfoList;
    }

    //更新数据表中的流程步骤处理状态信息
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Async
    public void asyncUpdateFlowStep(String tableName, String flowStep, String channelCode, String handleDate) {
        flowInfoMapper.asyncUpdateFlowStep(tableName, flowStep, channelCode, handleDate);
    }

    //插入解析的数据
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insertAnalysisData(String channelCode, String handleDate, String fileType, Integer stepCode, List<Map<String, Object>> dataList) {

        String flowStep = "stepCode_" + stepCode + ":success";
        switch (fileType) {
            case ConstUtil.FILE_TYPE_01:
                flowInfoMapper.deleteAnalysisData("account_apply", channelCode, handleDate);
                accountApplyMapper.insertAccountApply(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_03:
                flowInfoMapper.deleteAnalysisData("trans_apply", channelCode, handleDate);
                transApplyMapper.insertTransApply(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_31://TODO
                flowInfoMapper.deleteAnalysisData("el_contract_31", channelCode, handleDate);
                accountApplyMapper.insertAccountApply(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_43:
                flowInfoMapper.deleteAnalysisData("el_contract_43", channelCode, handleDate);
                elContract43Mapper.insertElContract43(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_R1:
                flowInfoMapper.deleteAnalysisData("non_resident_apply", channelCode, handleDate);
                nonResidentApplyMapper.insertNonResident(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_X1: //TODO
                flowInfoMapper.deleteAnalysisData("indi_fxq", channelCode, handleDate);
                accountApplyMapper.insertAccountApply(channelCode, handleDate, flowStep, dataList);
                break;
            case ConstUtil.FILE_TYPE_X3: //TODO
                flowInfoMapper.deleteAnalysisData("inst_fxq", channelCode, handleDate);
                accountApplyMapper.insertAccountApply(channelCode, handleDate, flowStep, dataList);
                break;
        }

    }

    //更新校验重复的appSheetSeralNo申请
    public void updateStatusAndMsgByAppSheetSerialNo(String tableName, String channelCode, String handleDate, List<String> sameAppSheetSerialNo, String errorMsg) {
        flowInfoMapper.updateStatusAndMsgByAppSheetSerialNo(tableName, channelCode, handleDate, sameAppSheetSerialNo, errorMsg);
    }

    //批量更新校验错误的数据
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateSerialNoAndCheckErrorList(String tableName, List<LinkedHashMap<String, Object>> dataList) {
        flowInfoMapper.updateSerialNoAndCheckErrorList(tableName, dataList);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void initCheckStatusAndErrorMsg(String tableName, String channelCode, String handleDate) {
        flowInfoMapper.initCheckStatusAndErrorMsg(tableName, channelCode, handleDate);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Map<String, String> selectFundMarketStatusMap(String channelCode, String handleDate) {
        List<MarketVo> marketVoList = marketMapper.selectMarketInfoList(channelCode, handleDate);
        return marketVoList.stream().collect(Collectors.toMap(
                MarketVo::getFundCode,
                MarketVo::getFundStatus,
                (key1, key2) -> key2
        ));
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void randomAllocationTaFundCode(String channelCode, String handleDate) {
        transApplyMapper.randomAllocationTaFundCode(channelCode, handleDate);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void recoverFailedData(String channelCode, String handleDate, Integer stepCode) {
        //表字段flowStep的最后拼接的是下面的key的，更新状态check_status为成功：1
        String key = "stepCode_" + stepCode + ":failed";

        flowInfoMapper.recoverFailedData("account_apply", channelCode, handleDate,key);
        flowInfoMapper.recoverFailedData("trans_apply", channelCode, handleDate,key);
        flowInfoMapper.recoverFailedData("el_contract_43", channelCode, handleDate,key);
        flowInfoMapper.recoverFailedData("non_resident_apply", channelCode, handleDate,key);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insertAccountStatus(LinkedHashMap<String, Object> account, String taAccountId) {
        String channelCode = MapUtils.getString(account,"CHANNELCODE");
        String transactionAccountId = MapUtils.getString(account,"TRANSACTIONACCOUNTID");

        AccountStatus accountStatus = accountStatusMapper.selectOne(new AccountStatus(channelCode,transactionAccountId));
        if(accountStatus == null) {
            String individualOrInstitution = MapUtils.getString(account, "INDIVIDUALORINSTITUTION");
            String certificateType = MapUtils.getString(account, "CERTIFICATETYPE");
            String certificateNo = MapUtils.getString(account, "CERTIFICATENO");
            String investorName = MapUtils.getString(account, "INVESTORNAME");
            accountStatusMapper.insert(new AccountStatus(channelCode,transactionAccountId,taAccountId,individualOrInstitution,certificateType,certificateNo,investorName));
        }
    }

    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public ResultVo sendTransBuyApplyToTa(LinkedHashMap<String, Object> trans) {

        LOGGER.info("交易调用TA购买接口的传入的数据为:{}", JsonUtil.getJson(trans));
        String channelCode = MapUtils.getString(trans,"CHANNELCODE");
        String handleDate = MapUtils.getString(trans,"HANDLEDATE");
        String fundCode = MapUtils.getString(trans,"FUNDCODE");
        String taFundCode = MapUtils.getString(trans,"TAFUNDCODE");
        String transactionAccountId = MapUtils.getString(trans,"TRANSACTIONACCOUNTID");
        BigDecimal applicationAmount = new BigDecimal(MapUtils.getString(trans,"APPLICATIONAMOUNT","0"));

        //账户信息
        AccountStatus accountStatus = accountStatusMapper.selectOne(new AccountStatus(channelCode,transactionAccountId));
        String fundAcco = accountStatus.getTaAccountId();

        //产品信息
        FundInfo fundInfo = fundInfoMapper.selectFundInfoByChannelAndFundCode(channelCode,fundCode);
        String payType = fundInfo.getPayType();
        Integer annual = fundInfo.getAnnualCalculateDays();
        Integer transRate = fundInfo.getTransRateFlag();
        String setUpDate = fundInfo.getSetUpDate();

        //TA 产品信息
        FundRelation fundRelation = fundRelationMapper.selectFundRelationByChannelAndFundAndTaFundCode(channelCode,fundCode,taFundCode);

        Integer setUpFlag = fundRelation.getSetUpFlag();

        String profitClass = "0";
        BigDecimal profit = new BigDecimal(0);
        //收益类别信息
        FundYield fundYield = fundYieldMapper.selectFundYield(channelCode,fundCode,applicationAmount);
        if(fundYield != null){
            profitClass = fundYield.getYieldType();
            profit = fundYield.getYieldRate();
        }

        //交易对应的唯一编号
        String outRequestNo = MapUtils.getString(trans,"TASERIALNO");
        String outContract = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME14) + sequenceMapper.getNextValue("outContractNo");
        String inContract= "";

        String isAppend = "0";//是否追加 0:否；1:是

        TransContract transContract = transContractMapper.selectOne(new TransContract(channelCode,fundCode,transactionAccountId,"01"));
        if(transContract != null){
            isAppend = "1";
            outContract = transContract.getOutContract();
            inContract = transContract.getInContract();
        }
        //组装数据
        LinkedHashMap<String,Object> requestMap = new LinkedHashMap<>();
        requestMap.put("FUNDCODE",taFundCode);
        requestMap.put("FUNDACCO",fundAcco);
        requestMap.put("BALANCE",applicationAmount);
        requestMap.put("PAYTYPE",payType);
        requestMap.put("TRANSRATE",transRate);
        requestMap.put("PROFITCLASS",profitClass);
        requestMap.put("PROFIT",profit);
        //业务标识 1：认购；2：申购；3：赎回
        requestMap.put("BUSINFLAG",setUpFlag == 0 ? "1" : "2");
        requestMap.put("OUTREQUESTNO",outRequestNo);
        requestMap.put("TRUSTCONTRACTID",outContract);
        requestMap.put("ISAPPEND",isAppend);
        requestMap.put("REQUESTDATE",handleDate);
        requestMap.put("INCOMEYEARDAYS",annual);
        requestMap.put("CONTRACTSERIALNO",inContract);
        requestMap.put("SETUPDATE",setUpDate);

        LOGGER.info("交易调用TA接口:【transBuy】的请求数据为:{}", JsonUtil.getJson(requestMap));

        ResultVo retVo = taService.transBuy(requestMap);

        LOGGER.info("交易调用TA接口:【transBuy】的返回结果为:{}", JsonUtil.getJson(retVo));

        return retVo;
    }

    public ResultVo sendTransRedeemApplyToTa(LinkedHashMap<String, Object> trans) {
        return ResultVo.ok();
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveElContractCfm(String channelCode, String handleDate, List<LinkedHashMap<String, Object>> elContract43List) {
        //删除已存在的数据
        elContract44Mapper.delete(new ElContract44(channelCode,handleDate));
        if(CollectionUtils.isNotEmpty(elContract43List)) {
            //插入44确认表
            elContract44Mapper.insertElContract44(elContract43List);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveNonResidentCfm(String channelCode, String handleDate, List<LinkedHashMap<String, Object>> nonResidentForCfmList) {
        //删除已存在的数据
        nonResidentCfmMapper.delete(new NonResidentCfm(channelCode,handleDate));

        if(CollectionUtils.isNotEmpty(nonResidentForCfmList)) {
            //插入R2确认表
            nonResidentCfmMapper.insertNonResidentCfm(nonResidentForCfmList);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveAccountCfm(String channelCode, String handleDate, List<LinkedHashMap<String, Object>> accountCfmList) {
        //删除已存在的数据
        accountCfmMapper.delete(new AccountCfm(channelCode,handleDate));

        if(CollectionUtils.isNotEmpty(accountCfmList)) {
            //插入账户确认表
            accountCfmMapper.insertAccountCfm(accountCfmList);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveTransCfm(String channelCode, String handleDate, List<LinkedHashMap<String, Object>> transForCfmList) {
        //删除已存在的数据
        transCfmMapper.delete(new TransCfm(channelCode,handleDate));

        if(CollectionUtils.isNotEmpty(transForCfmList)) {
            //插入04确认表
            transCfmMapper.insertTransCfm(transForCfmList);
        }
    }

    /**
     * 查询错误交易和120认购成功数据
     *
     * @param channelCode     渠道编码
     * @param lastDay         该渠道上一交易日
     * @param handleDate      当前处理日期
     * @param transForCfmList 交易确认数据
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public void select020AndErrorCfm(String channelCode, String lastDay, String handleDate, List<LinkedHashMap<String, Object>> transForCfmList) {
        /**
         * 1、120数据
         * 2、错误数据
         */
        List<LinkedHashMap<String, Object>> trans020CfmList = transApplyMapper.selectTrans020ForCfm(channelCode,lastDay,handleDate);
        if(CollectionUtils.isNotEmpty(trans020CfmList)) {
            LOGGER.info("查询的{}渠道,{}日的020认购的申请数据数量为:{}", channelCode, lastDay, trans020CfmList.size());
            transForCfmList.addAll(trans020CfmList);
        }

        List<LinkedHashMap<String, Object>> transErrorCfmList = transApplyMapper.selectTransErrorForCfm(channelCode,lastDay,handleDate);
        if(CollectionUtils.isNotEmpty(transErrorCfmList)) {
            LOGGER.info("查询的{}渠道,{}日的失败的申请数据数量为:{}", channelCode, lastDay, transErrorCfmList.size());
            transForCfmList.addAll(transErrorCfmList);
        }
    }
}

